package com.zhou.project.configurations.shiro;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.zhou.project.configurations.shiro.realm.CustomRealm;
import org.apache.shiro.mgt.SessionsSecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import java.util.Properties;

/**
 * @author zhouhonggang
 * @version 1.0.0
 * @project spring-boot-project
 * @datetime 2022-03-07 16:41
 * @description: TODO
 */
@Configuration
public class ApacheShiroConfigurations {

    /**
     * 自定义Realm实现登录权限
     * @return CustomRealm
     */
    @Bean
    public Realm customRealm()
    {
        return new CustomRealm();
    }

    /**
     * 权限管理器
     * @return DefaultWebSecurityManager
     */
    @Bean
    public SessionsSecurityManager securityManager()
    {
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(customRealm());
        return defaultWebSecurityManager;
    }

    /**
     * 配置URL权限拦截规则
     * @return ShiroFilterChainDefinition
     */
    @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition()
    {
        DefaultShiroFilterChainDefinition defaultShiroFilterChainDefinition = new DefaultShiroFilterChainDefinition();
        //登录资源放行
        defaultShiroFilterChainDefinition.addPathDefinition("/auth/unlog", "anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/auth/login", "anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/css/**", "anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/img/**", "anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/webjars/**", "anon");
        //其他资源需认证
        defaultShiroFilterChainDefinition.addPathDefinition("/**", "authc");
        return defaultShiroFilterChainDefinition;
    }

    /**
     * Thymeleaf整合Shiro标签库
     * @return ShiroDialect
     */
    @Bean
    public ShiroDialect shiroDialect()
    {
        return new ShiroDialect();
    }

    /**
     * 当无权限访问时跳转指定页面
     * @return SimpleMappingExceptionResolver
     */
    @Bean
    public SimpleMappingExceptionResolver simpleMappingExceptionResolver()
    {
        SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
        Properties properties = new Properties();
        properties.setProperty("UnauthorizedException", "/403.html");
        simpleMappingExceptionResolver.setExceptionMappings(properties);
        return simpleMappingExceptionResolver;
    }

    /**
     * setUsePrefix(false)用于解决一个奇怪的bug。在引入spring aop的情况下。
     * 在@Controller注解的类的方法中加入@RequiresRole等shiro注解，会导致该方法无法映射请求，导致返回404。
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator()
    {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setUsePrefix(true);
        return defaultAdvisorAutoProxyCreator;
    }
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor()
    {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }

}
